#pragma once

#include <string>
#include <iostream>

/**
 * FIFO Queue 
 * 队列的设计，先进先出，只从尾进，只从头出
 * 队列内元素的遍历和查看
 * 队列内是数据链表结构，头尾指针，头指针指向队列头，尾指针指向队列尾
*/
template<class T>
class Tp 
{
public:
    T * qt;
    Tp * next;
    Tp(T * qt, Tp * next=nullptr):qt(qt),next(next){}
};

template<class T>
class QueueTp
{
private:
    Tp<T> *first_item=nullptr;
    Tp<T> *last_item=nullptr;
    int queue_deepth;
    int top;
public:
    QueueTp(int s=10);
    ~QueueTp();
    bool isempty() const {return first_item==nullptr;}
    bool isfull() const {return queue_deepth==top;}
    bool enqueue(T* item);
    bool dequeue(T* item);
    void show() const;
};

template<class T>
QueueTp<T>::QueueTp(int s):queue_deepth(s),top(0)
{
}

template<class T>
QueueTp<T>::~QueueTp()
{
}
template<class T>
bool QueueTp<T>::enqueue(T* item){
    if(top < queue_deepth)
    {
        Tp<T> * tmp = new Tp<T> (item);
        if (first_item == nullptr)
        {
            first_item = last_item = tmp;
        }
        else
        {
            last_item->next = tmp;
            last_item = tmp;    
        }
        top++;
        return true;
    }
    else
        return false;
}

template<class T>
bool QueueTp<T>::dequeue(T* item){
    if(top > 0)
    {
        Tp<T>* old = first_item;
        *item = *(old->qt);
        first_item = first_item->next;
        delete old;
        top--;
        if (top == 0)
            last_item = nullptr;
        return true;
    }
    else
        return false;
}

template<class T>
void QueueTp<T>::show() const{
    std::cout<< "QueueTp full depth "<< queue_deepth << " has " << top <<" items."<< std::endl;
    Tp<T>* tmp;
    tmp = first_item;
    while (tmp != nullptr)
    {
        (*tmp->qt)->show();
        tmp = tmp->next;
        std::cout<< std::endl;
    }
}

class Worker
{
private:
    std::string fullname_;
    long id_;
    std::string type() const {return "Worker";}
protected:
    virtual void data() const;
    virtual void get();
public:
    Worker() :fullname_("None"),id_(0){}
    Worker(const std::string &s,long n):fullname_(s),id_(n){}
    virtual ~Worker()=0;
    virtual void set()=0;
    virtual void show() const=0;
};

class Waiter: virtual public Worker
{
private:
    int panache;
    std::string type()const{return "Waiter";}
protected:
    void data() const;
    void get();
public:
    Waiter():Worker(),panache(0){}
    Waiter(const std::string &s, long n,int p=0):Worker(s,n),panache(p){}
    Waiter(const Worker &s, int p=0):Worker(s),panache(p){}
    ~Waiter(){}
    void set();
    void show() const;
};

class Singer: virtual public Worker
{
protected:
    enum{other,alto,contralto,soprano,bass,baritone,tenor};
    enum{Vtypes=7};
    void data() const;
    void get();
private:
    static const char * pv[Vtypes];
    int voice;
    std::string type()const{return "Singer";}
public:
    Singer():Worker(),voice(other){}
    Singer(const std::string &s, long n, int v=other):Worker(s,n),voice(v){}
    Singer(const Worker &s, int v=other):Worker(s),voice(v){}
    ~Singer(){}
    void set();
    void show() const;
};

class WaiterSinger: public Waiter, public Singer
{
    protected:
        void data() const;
        void get();
    public:
        WaiterSinger():Worker(),Waiter(),Singer(){}
        WaiterSinger(const std::string &s, long n, int p=0, int v=other):Worker(s,n),Waiter(s,n,p),Singer(s,n,v){}
        WaiterSinger(const Worker &w, int p=0, int v=other):Worker(w),Waiter(w,p),Singer(w,v){};
        WaiterSinger(const Waiter &w, int v=other):Worker(w),Waiter(w),Singer(w,v){};
        WaiterSinger(const Singer &w, int p=0):Worker(w),Waiter(w,p),Singer(w){};
        ~WaiterSinger(){}
        void set();
        void show() const;
};
